﻿//-----------------------------------------------------------------------
// <copyright file="Copyright.cs" author="Michael Herndon">
//     Copyright (c) Michael Herndon & Ashish Tonse.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Cid.Data
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;
	using System.Data;

	using Cid.Diagnostics;

	public class Adapter
	{
		private string connectionString = "";

		public Adapter() { }

		public Adapter(string connectionString)
		{
			this.connectionString = connectionString;
		}

		public string Quote(object value)
		{
			return this.Quote(value, null);
		}

		public string Quote(object value, System.Data.Linq.Mapping.ColumnAttribute column)
		{
			if (value == null)
				return "NULL";

			Log.Debug(value.GetType().ToString());
			switch (value.GetType().ToString())
			{
				case "System.String":
					if (column != null && new string[] { "integer", "float" }.Contains(column.DbType))
					{
						object temp = (column.DbType == "integer") ? Convert.ToInt32(value) : Convert.ToSingle(value);
						return temp.ToString();
					}
					return QuoteString(value.ToString());
				case "System.Guid":
					return QuoteString(value.ToString().ToLower());
				case "System.Byte[]":
					throw new ArgumentException("All binary values must be passed into an sql parameter");
				case "System.Boolean":
					if (column != null && column.DbType == "integer")
						return (Convert.ToBoolean(value)) ? "1" : "0";
					else
						return (Convert.ToBoolean(value)) ? this.QuotedTrue : this.QuotedFalse;
				case "System.Decimal":
					return value.ToString();
				case "System.DateTime":
					return QuotedDate((DateTime)value);
				default:
					return QuoteString(value.ToString());
			}
		}

		public virtual string QuoteString(string value)
		{
			return string.Format("'{0}'", value.Replace("'", "''"));
		}

		public virtual string QuoteColumnName(string name)
		{
			return string.Format("[{0}]", name);
		}

		public virtual string QuoteTableName(string name)
		{
			return string.Format("[{0}]", name);
		}

		public virtual string QuotedTrue
		{
			get { return "1"; }
		}

		public virtual string QuotedFalse
		{
			get { return "0"; }
		}

		public virtual string QuotedDate(DateTime value)
		{
			return this.QuoteString(value.ToString("MM-dd-yyyy HH:mm:ss"));
		}

		public virtual IDbConnection Connect()
		{
			return new System.Data.SqlClient.SqlConnection(this.connectionString);
		}


		public IDataReader ExecuteReader(string sql, params object[] values)
		{
			using (IDbConnection connection = Connect())
			{
				connection.Open();
				try
				{
					IDbCommand command = connection.CreateCommand();
					command.CommandType = CommandType.Text;

					if (values != null)
					{
						values.Each(delegate(object value)
						{
							IDataParameter param = command.CreateParameter();
							string name = string.Format("{0}Parameter{1}", "@", command.Parameters.Count);
							param.ParameterName = name;
							param.Value = value;
							values.SetValue(name, command.Parameters.Count);
							command.Parameters.Add(param);
						});
						command.CommandText = string.Format(sql, values);

					}
					else
						command.CommandText = sql;

					Log.Sql(command.CommandText);

					return command.ExecuteReader(CommandBehavior.CloseConnection);
				}
				catch
				{
					connection.Close();
					throw;
				}
			}
		}

		public object ExecuteScalar(string sql, params object[] values)
		{
			using (IDbConnection connection = Connect())
			{
				connection.Open();
				IDbTransaction tr = connection.BeginTransaction();
				try
				{
					IDbCommand command = connection.CreateCommand();
					command.Transaction = tr;
					command.CommandType = CommandType.Text;
					if (values != null)
					{
						values.Each(delegate(object value)
						{
							IDataParameter param = command.CreateParameter();
							string name = string.Format("{0}Parameter{1}", "@", command.Parameters.Count);
							param.ParameterName = name;
							param.Value = value;
							values.SetValue(name, command.Parameters.Count);
							command.Parameters.Add(param);
						});
						command.CommandText = string.Format(sql, values);

					}
					else
						command.CommandText = sql;

					Log.Sql(command.CommandText);

					object o = command.ExecuteScalar();
					tr.Commit();
					return o;
				}
				catch
				{
					tr.Rollback();
					tr.Dispose();
					tr = null;
					throw;
				}
			}
		}

		public int ExecuteNonQuery(string sql, params object[] values)
		{
			return ExecuteNonQuery(sql, true, values);
		}

		public int ExecuteNonQuery(string sql, bool useTransaction, params object[] values)
		{
			int temp = 0;
			using (IDbConnection connection = Connect())
			{
				connection.Open();

				IDbTransaction tr = null;

				if (useTransaction)
					tr = connection.BeginTransaction();
				try
				{
					IDbCommand command = connection.CreateCommand();

					if (useTransaction)
						command.Transaction = tr;
					command.CommandType = CommandType.Text;
					if (values != null)
					{
						values.Each(delegate(object value)
						{
							IDataParameter param = command.CreateParameter();
							string name = string.Format("{0}Parameter{1}", "@", command.Parameters.Count);
							param.ParameterName = name;
							param.Value = value;
							values.SetValue(name, command.Parameters.Count);
							command.Parameters.Add(param);
						});
						command.CommandText = string.Format(sql, values);
					}
					else
						command.CommandText = sql;

					Log.Sql(command.CommandText);

					temp = command.ExecuteNonQuery();
					if(tr != null)
						tr.Commit();
				}
				catch
				{
					if (tr != null)
						tr.Rollback();
					throw;
				}
				finally
				{
					if (tr != null)
					{
						tr.Dispose();
						tr = null;
					}
				}
				return temp;
			}
		}
	}
}
